/*
 * Created on 25.06.2006 by leck
 *
 */
package de.devisnik.eidle.flashlight;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Region;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

import de.devisnik.eidle.picture.ImageUtils;
import de.devisnik.eidle.util.ScreenWithDuration;

public class FlashlightScreen extends ScreenWithDuration {

	private double itsRelativeDiameter;

	private Composite itsCanvas;

	private ControlAdapter itsResizeListener;

	private PaintListener itsPaintListener;

	private Image itsScaledImage;

	private MultiShapeSpot itsCircleSpot;

	private void updateRadius(final double relativeDiameter) {
		setRelativeDiameter(relativeDiameter);
		itsCircleSpot.setRadius(getRadius(itsCanvas));
	}

	private final ImageDescriptor descriptor;

	public FlashlightScreen(final ImageDescriptor descriptor, final int duration) {
		super("Flashlight", duration);
		Assert.isNotNull(descriptor);
		this.descriptor = descriptor;
	}

	private Image getImage(final Display display) {
		return descriptor.createImage();
	}

	private void setRelativeDiameter(final double relativeDiameter) {
		if (relativeDiameter > 0 && relativeDiameter < 1) {
			itsRelativeDiameter = relativeDiameter;
		}
	}

	private double getRelativeDiameter() {
		if (itsRelativeDiameter == 0) {
			itsRelativeDiameter = FlashlightPreferences.getRelativeDiameter() / 100f;
		}
		return itsRelativeDiameter;
	}

	private int getRadius(final Composite parent) {
		final int min = Math.min(parent.getSize().x, parent.getSize().y);
		final int radius = (int) (min * getRelativeDiameter()) / 2;
		return radius;
	}

	public void createControl(final Composite parent) {
		super.createControl(parent);
		final Display display = parent.getDisplay();
		itsCircleSpot = new MultiShapeSpot(FlashlightPreferences
				.getSpotNumber(), getRadius(parent), new ShapeFactory());
		itsCanvas = new Canvas(parent, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE
				| SWT.NO_MERGE_PAINTS);
		final Image originalImage = getImage(display);
		itsScaledImage = ImageUtils.getScaledImage(display, originalImage,
				display.getBounds());
		originalImage.dispose();
		itsPaintListener = new PaintListener() {

			public void paintControl(final PaintEvent e) {
				final Image image = itsScaledImage;
				final Region dirtyRegion = new Region();
				dirtyRegion.add(e.x, e.y, e.width, e.height);
				final Region clippingRegion = new Region();
				clippingRegion.add(itsCircleSpot.getRegion());
				dirtyRegion.subtract(clippingRegion);
				e.gc.setClipping(clippingRegion);
				e.gc.drawImage(image, e.x, e.y, e.width, e.height, e.x, e.y,
						e.width, e.height);
				clippingRegion.dispose();
				e.gc.setClipping(dirtyRegion);
				e.gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
				e.gc.fillRectangle(e.x, e.y, e.width, e.height);
				dirtyRegion.dispose();
			}
		};
		itsCanvas.addPaintListener(itsPaintListener);
		itsResizeListener = new ControlAdapter() {
			public void controlResized(final ControlEvent e) {
				itsScaledImage.dispose();
				final Image originalImage = getImage(display);
				itsScaledImage = ImageUtils.getScaledImage(display,
						originalImage, itsCanvas.getBounds());
				originalImage.dispose();
				itsCircleSpot.setRadius(getRadius(itsCanvas));
				itsCanvas.redraw();
			}
		};
		itsCanvas.addControlListener(itsResizeListener);
		display.asyncExec(new SpotMover(itsCanvas, itsCircleSpot));
	}

	public void disposeControl() {
		if (!itsCanvas.isDisposed()) {
			itsCanvas.removeControlListener(itsResizeListener);
			itsCanvas.removePaintListener(itsPaintListener);
			itsCanvas.dispose();
		}
		itsScaledImage.dispose();
		itsCircleSpot.dispose();
		super.disposeControl();
	}

	public void dispose() {
	}

	public void setFocus() {
		itsCanvas.setFocus();
	}

	public void bigger() {
		updateRadius(itsRelativeDiameter * 1.05f);
		itsCanvas.redraw();
	}

	public void smaller() {
		updateRadius(itsRelativeDiameter / 1.05f);
		itsCanvas.redraw();
	}
	
	public void turnLeft() {
		itsCircleSpot.turnLeft();
		itsCanvas.redraw();
	}

	public void turnRight() {
		itsCircleSpot.turnRight();
		itsCanvas.redraw();
	}
	
}
